import socket
import re
import time
import struct
from get_config import *
#import numpy as np

def get_number(s):
    if isinstance(s, str):
        a = ''.join(list(filter(str.isdigit, s)))
    else:
        a = s
    return int(a)

def get_fmt(word_num, isuint):
    b = '<' if 1 else '>'
    t = ' hi'
    if isuint:
        t = t.upper()
    f = b+t[word_num]
    return f

class McPlc():
    def __init__(self,host,port):
        self.host = host
        self.port = port
        self.client = None
        self.ConnectServer()
    
    def reopen(self):
        self.CloseSocket()
        self.ConnectServer()

    def CloseSocket(self):
        if self.client is None:
            return None
        self.client.close()
        self.client = None
        logger.info('McPlc.CloseSocket')
        return 0

    def ConnectServer(self):
        client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            #client.connect((host, port))
            client.connect((self.host, self.port))
        except Exception as e:
            logger.info(f"Connection error: {str(e)} {self.host} {self.port}")
            return False
        logger.info(f'McPlc.ConnectServer ok {self.host} {self.port}')
        client.settimeout(5)
        self.client = client
        return True

    def ReadInt_(self, adress, word_num, isuint=True):  #读D40结束拍照信号
        if self.client is None:
            logger.info("error: client is None")
            return None
        # 最终用了ASCII码的方式
        # word_num 1 = int16
        # word_num 2 = int132
        try:
            adress = get_number(adress)
            str1 = f'01 FF 0A 00 {adress:02x} 00 00 00 20 44 0{word_num} 00'
            #logger.info(str1)
            bytes1 = bytes.fromhex(str1)
            # msg = np.fromstring(str1, dtype=np.uint8)
            self.client.send(bytes1)
            #time.sleep(0.2)
            res = self.client.recv(1024)
            #logger.info(res)
            ss = res.hex()

            if ss.startswith('8100') or ss.startswith('8300'):
                # logger.info(res.hex())
                ss1 = ss[4:]
                #logger.info(ss)
                nss = word_num*4
                if len(ss1)<nss:
                    return None
                if len(ss1)>nss:
                    ss1 = ss1[:nss]
                bytes1 = bytes.fromhex(ss1)
                f = get_fmt(word_num, isuint)
                end = struct.unpack(f, bytes1)[0]
                #end = int(ss1, 16)
                return end
            else:
                return None
                
        except Exception as e:
            logger.info(f'McPlc.ReadInt_ 读结束信号失败 {str(e)} {adress} {word_num}')
            self.reopen()
            return None
        return None
    
    def ReadInt16(self, adress):  #读D40结束拍照信号
        # 最终用了ASCII码的方式
        return self.ReadInt_(adress, 1)

    def ReadInt32(self, adress):  #读D40结束拍照信号
        # 最终用了ASCII码的方式
        return self.ReadInt_(adress, 2)

    def WriteInt16(self,address,index, word_num=1, isuint=False):  #D10写入产品信息 adress=10,index写入的值,30 NG1，复位2
        if self.client is None:
            logger.info("error: client is None")
            return None
        try:
            address = get_number(address)
            index = int(index)
            if word_num==1:
                index = index & 0xffff 
            f = get_fmt(word_num, isuint)
            end = struct.pack(f, index)
            end1 = ['%02x' % i for i in end]
            end1 = ' '.join(end1)
            str1 = f'03 FF 0A 00 {address:02x} 00 00 00 20 44 0{word_num} 00 {end1}'
            bytes1 = bytes.fromhex(str1)
            # msg = np.fromstring(str1, dtype=np.uint8)
            self.client.send(bytes1)
            return len(bytes1)
        except Exception as e:
            logger.info(f'McPlc.WriteInt16 {str(e)} {address} {index} {word_num}')
            self.reopen()
            return None

def test_McPlc():
    import time
    host = '192.168.1.20'
    # a = is_open(host)
    plcr = McPlc(host, 8080)  # 读某个寄存器中的内容
    #plcw = McPlc(host, 8090)  # 读某个寄存器中的内容
    for i in range(10):
        logger.info(plcr.ReadInt16('D60'))
        logger.info(plcw.WriteInt16('D60', 0))
        logger.info(plcr.ReadInt16('D62'))
        logger.info(plcr.ReadInt16('D100'))
        time.sleep(1)

    return 0


if __name__ == "__main__":
    test_McPlc()